#include "AnimationSet.h"
#include "Macro.h"
#include <sstream>

namespace Graphics
{
	AnimationSet::AnimationSet(void):m_Speed(1.0f),m_ID(0),m_State(ANI_PLAYING)
	{
	}
	AnimationSet::~AnimationSet(void)
	{
		for(size_t i=0;i<m_Animations.size();i++)
		{
			delete m_Animations[i];
		}
	}


	bool AnimationSet::RenderImpl(void)
	{
		int id = this->GetID();
		if(id>=0 && id<(int)m_Animations.size())
		{
			m_Animations[id]->SetSpeed(this->GetSpeed());
			m_Animations[id]->SetPos(this->GetPos().x,this->GetPos().y);
			m_Animations[id]->SetVisible(true);
			m_Animations[id]->Render();
			m_Animations[id]->SetVisible(false);
		}
		return true;
	}

    void AnimationSet::SetViewport(Viewport* viewport)
    {
        Renderable2D::SetViewport(viewport);
        for(size_t i=0;i<m_Animations.size();i++)
        {
            m_Animations[i]->SetViewport(viewport);
        }
    }
		
	bool AnimationSet::LoadXML(const MSXML2::IXMLDOMNodePtr& pNode)
	{
		if(pNode == 0)
		{
			return false;
		}

		try
		{
			m_Description = (std::string)pNode->attributes->getNamedItem("description")->text;
		}
		catch(...)
		{
			return false;
		}

		MSXML2::IXMLDOMNodePtr pAniNode = pNode->selectSingleNode("Animations");
		MSXML2::IXMLDOMNodePtr pTextureNode = pNode->selectSingleNode("Textures");

		if(pAniNode == 0 || pTextureNode == 0)
		{
			return false;
		}
		MSXML2::IXMLDOMNodeListPtr pAniList = pAniNode->selectNodes("Animation");
		MSXML2::IXMLDOMNodeListPtr pTextureList = pTextureNode->selectNodes("Texture");
		if(pAniList == 0 || pTextureList == 0)
		{
			return false;
		}

		m_Animations.clear();
		m_Names.clear();

		try
		{
			for(int i=0;i<pAniList->length;i++)
			{
				// Store the animation
				AnimationImpl* pAni = new AnimationImpl();
                pAni->SetVisible(false);
                pAni->SetViewport(this->GetViewport());
				m_Animations.push_back(pAni);

				MSXML2::IXMLDOMDocumentPtr pDoc;
				
				HRESULT hr= pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30));
				if (FAILED(hr)) 
				{
					return false;
				}
				// The default is true.
				pDoc->async = VARIANT_FALSE;
				
				// Store the name
				m_Names.push_back((std::string)pAniList->item[i]->attributes->getNamedItem("name")->text);

				// Load a animation file
				_bstr_t& file = pAniList->item[i]->attributes->getNamedItem("file")->text;
				if(pDoc->load(file)!=VARIANT_TRUE)
				{
				  return false;
				}
				MSXML2::IXMLDOMNodePtr pRootNode = pDoc->selectSingleNode("Animation");
				if(!pAni->LoadXML(pRootNode))
				{
					throw(std::exception());
				}

				// Create the texture list
				MSXML2::IXMLDOMNodePtr pTextures = pDoc->createNode(NODE_ELEMENT,"textures","");
				std::string str = (std::string)pAniList->item[i]->attributes->getNamedItem("textures")->text;
				const char* strlist = str.c_str();
				int index = 0;
				while(*strlist != 0)
				{
					if(*strlist == ',')
					{
						pTextures->appendChild(pTextureList->item[index]);
						index = 0;
					}
					else
					{
						index = index * 10 + (*strlist)-'0';
					}
					strlist ++;
				}
				pTextures->appendChild(pTextureList->item[index]);
				if(!pAni->LoadTextureXML(pTextures))
				{
					throw(std::exception());
				}

                // get the offset id
                try
                {
                    int offsetID = atoi(pAniList->item[i]->attributes->getNamedItem("offset_id")->text);
                    pAni->SetOffsetID(offsetID);
                }catch(...)
                {
                    // do nothing
                }
			}
			return true;
		}
		catch(...)
		{
			m_Animations.clear();
			m_Names.clear();
			return false;
		}

	}

	bool AnimationSet::Load(std::string filename)
	{
		HRESULT hr;
		MSXML2::IXMLDOMDocumentPtr pDoc;
		
		CoInitialize(NULL);
		hr= pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument30));
		if (FAILED(hr)) 
		{
			return false;
		}

		// The default is true.
		pDoc->async = VARIANT_FALSE;
		
		// Load a xml file
		if(pDoc->load((_variant_t)filename.c_str())!=VARIANT_TRUE)
		{
		  return false;
		}
		
		MSXML2::IXMLDOMNodePtr	pRootNode = pDoc->selectSingleNode("AnimationSet");

		bool result = this->LoadXML(pRootNode);

		pRootNode.Release();
		pDoc.Release();
		CoUninitialize();
		
		return result;
	}

	//float AnimationSet::GetSpeed(void)
	//{
	//	return m_Speed;
	//}
	//int AnimationSet::GetID(void)
	//{
	//	return m_ID;
	//}

	ANI_STATE AnimationSet::Play(void)
	{
		return m_State = ANI_PLAYING;
	}
	ANI_STATE AnimationSet::Stop(void)
	{
		return m_State = ANI_STOP;
	}

	ANI_STATE AnimationSet::GetState(void)
	{
		return m_State;
	}
	
	//void AnimationSet::SetSpeed(float speed)
	//{
	//	if(speed <= 0.0f)
	//	{
	//		return;
	//	}
	//	m_Speed = speed;
	//}
	//void AnimationSet::SetID(int id)
	//{
	//	if(id >= 0)
	//	{
	//		m_ID = id;
	//	}
	//}
	int AnimationSet::NameToID(std::string& name)
	{
		for(size_t i = 0; i < m_Names.size(); i++)
		{
			if(m_Names[i].compare(name) == 0)
			{
				return (int)i;
			}
		}
		return -1;
	}
	const std::string& AnimationSet::GetDescription(void)
	{
		return m_Description;
	}
}
namespace Graphics
{
	AnimationSet::AnimationImpl::AnimationImpl(void):m_Pos(0,0)
	{
	}
	AnimationSet::AnimationImpl::~AnimationImpl(void)
	{
	}

	// set the position of sprite
	void AnimationSet::AnimationImpl::SetPos(int x, int y)
	{
		m_Pos.Set(x,y);
	}
	const Position& AnimationSet::AnimationImpl::GetPos(void)
	{
		return m_Pos;
	}
}